// internal/model/comment_batcher.go
package model

import (
	"blogcenter/internal/types"
	"context"
	"errors"
	"sync"
	"time"

	"github.com/zeromicro/go-zero/core/logx"
)

const (
	BatchSize     = 100
	FlushInterval = 5 * time.Second
	MaxQueueSize  = 1000
)

type CommentBatcher struct {
	service   CommentModel
	queue     chan *commentTask
	closeChan chan struct{}
	wg        sync.WaitGroup
}

type commentTask struct {
	req       *types.CommentRequest
	commentID uint
	ctx       context.Context
}

func NewCommentBatcher(service CommentModel) *CommentBatcher {
	return &CommentBatcher{
		service:   service,
		queue:     make(chan *commentTask, MaxQueueSize),
		closeChan: make(chan struct{}),
	}
}

func (b *CommentBatcher) Add(ctx context.Context, req *types.CommentRequest, commentID uint) error {
	select {
	case b.queue <- &commentTask{ctx: ctx, req: req, commentID: commentID}:
		return nil
	default:
		return errors.New("评论处理队列已满，请稍后重试")
	}
}

func (b *CommentBatcher) Start() {
	// 启动3个处理协程
	for i := 0; i < 3; i++ {
		b.wg.Add(1)
		go b.processLoop()
	}
}

func (b *CommentBatcher) Stop() {
	close(b.closeChan)
	b.wg.Wait()
	b.flushRemaining()
}

func (b *CommentBatcher) processLoop() {
	defer b.wg.Done()

	batch := make([]*commentTask, 0, BatchSize)
	ticker := time.NewTicker(FlushInterval)
	defer ticker.Stop()

	for {
		select {
		case task := <-b.queue:
			batch = append(batch, task)
			if len(batch) >= BatchSize {
				b.processBatch(batch)
				batch = batch[:0]
			}

		case <-ticker.C:
			if len(batch) > 0 {
				b.processBatch(batch)
				batch = batch[:0]
			}

		case <-b.closeChan:
			if len(batch) > 0 {
				b.processBatch(batch)
			}
			return
		}
	}
}

// blogcenter/internal/model/commentbatcher.go
func (b *CommentBatcher) processBatch(tasks []*commentTask) error {
	if len(tasks) == 0 {
		return nil
	}

	ctx := tasks[0].ctx
	logger := logx.WithContext(ctx)

	// 1. 准备批量数据
	indexes := make([]*CommentIndex, 0, len(tasks))
	contents := make([]*CommentContent, 0, len(tasks))
	subjectUpdates := make(map[uint]struct{}) // 去重记录需要更新的主题

	for _, task := range tasks {
		// 1.1 确保主题存在
		if err := b.service.EnsureSubject(ctx, task.req.ObjectID, task.req.ObjectType, int(task.req.UserID)); err != nil {
			logger.Errorf("主题检查失败 object_id=%d: %v", task.req.ObjectID, err)
			continue
		}

		// 1.2 构建索引
		indexes = append(indexes, &CommentIndex{
			ObjectId:   task.req.ObjectID,
			ObjectType: task.req.ObjectType,
			UserId:     int(task.req.UserID),
			Root:       int(task.req.RootID),
			Parent:     int(task.req.ParentID),
			LikeCount:  0,
			Attrs:      0,
		})

		// 1.3 构建内容
		contents = append(contents, &CommentContent{
			Content: task.req.Content,
		})

		// 记录需要更新的主题
		subjectUpdates[task.req.ObjectID] = struct{}{}
	}

	// 2. 批量插入
	if len(indexes) == 0 {
		return errors.New("无有效数据可处理")
	}

	if err := b.service.BatchInsertComments(ctx, indexes, contents); err != nil {
		logger.Errorf("批处理失败: %v (共%d条评论)", err, len(indexes))
		return err
	}

	// 3. 批量更新计数（优化版）
	for objectID := range subjectUpdates {
		isRoot := tasks[0].req.ParentID == 0 // 假设同批次parent相同
		count := len(tasks)
		if err := b.service.UpdateSubjectCount(ctx, objectID, tasks[0].req.ObjectType, isRoot, count); err != nil {
			logger.Errorf("更新计数失败 object_id=%d: %v", objectID, err)
		}
	}

	logger.Infof("成功处理 %d 条评论（涉及 %d 个主题）", len(indexes), len(subjectUpdates))
	return nil
}

func (b *CommentBatcher) flushRemaining() {
	for {
		select {
		case task := <-b.queue:
			b.processBatch([]*commentTask{task})
		default:
			return
		}
	}
}
